package ui;

import cn.hutool.core.date.DateUtil;
import entity.MainJFrame;
import lombok.Setter;
import util.*;
import entity.Record;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.util.Objects;
import java.util.Random;

public class GameGUI extends MainJFrame {
    private int x, y;
    private ImageView imageView;
    private final int rows;
    private final int cols;
    private Timer timer;
    private int step;
    private long time;
    private JLabel stepLabel;
    private JLabel timeLabel;
    private JPanel infoPanel;
    /**
     *
     * 当前图片
     */
    @Setter
    private String dirPath;

    public GameGUI() {
        super();
        String onlineUsername = UserManager.getOnlineUser().getUsername();

        this.rows = JsonRW.getInt(JsonRW.configFile, "rows");
        this.cols = JsonRW.getInt(JsonRW.configFile, "cols");

        int width = JsonRW.getInt(JsonRW.configFile, "widthWhole");
        int height = JsonRW.getInt(JsonRW.configFile, "heightWhole");

        String runPath = JsonRW.getStr(JsonRW.configFile, "runPath");

        ImageHandle.splitImages(JsonRW.getStr(JsonRW.configFile, "userDataDir") + "/" + onlineUsername + "/images",
                runPath, rows, cols, width, height);

        this.step = 0;
        this.time = 0;

        this.dirPath = runPath + "/0";

        setSize(400, 400);
        initComponents();
        enableInputMethods(false);

        setFocusable(true);
        requestFocus();
        setLocationRelativeTo(null);
        setAlwaysOnTop(true);

        setVisible(true);

        dealWithLogic();
    }

    private void dealWithLogic() {
        timer = new Timer(1000, _ -> {
            time++;
            // 实时更新显示
            updateInfoDisplay();
        });

        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                int code = e.getKeyCode();
                if (isGameOver()) {
                    dealAfterGameOver();
                } else {
                    if (code == KeyEvent.VK_LEFT || code == KeyEvent.VK_UP ||
                            code == KeyEvent.VK_RIGHT || code == KeyEvent.VK_DOWN) {
                        timer.start();
                        move(code);
                        updateInfoDisplay();
                        imageView.repaint();
                        if (isGameOver()) {
                            dealAfterGameOver();
                        }
                    }
                }

                if (code == KeyEvent.VK_Q) {
                    Graphics g = imageView.getGraphics();
                    imageView.loadOrUpdateImageResources(g, imageView.getImage(), 0, 0, imageView.getWidth(), imageView.getHeight());
                    g.dispose();
                }
            }

            @Override
            public void keyReleased(KeyEvent e) {
                int code = e.getKeyCode();
                if (code == KeyEvent.VK_Q) {
                    Graphics g = imageView.getGraphics();
                    imageView.drawCroppedImages(g);
                    repaint();
                    g.dispose();
                }
            }
        });
    }

    private boolean isGameOver() {
        if (x != rows - 1 || y != cols - 1) {
            return false;
        }
        for (int i = 0; i < rows - 1; i++) {
            for (int j = 0; j < cols; j++) {
                if (imageView.getDataElement(i, j) != i * cols + j + 1) {
                    return false;
                }
            }
        }

        for (int i = rows - 1, j = 0; j < cols - 1; j++) {
            if (imageView.getDataElement(i, j) != i * cols + j + 1) {
                return false;
            }
        }
        return imageView.getDataElement(rows - 1, cols - 1) == 0;
    }

    /**
     * time为 0 说明是调用一键通关获胜的，不予记录
     */
    private void dealAfterGameOver() {
        if (timer != null && timer.isRunning()) {
            timer.stop();
        }
        JOptionPane.showOptionDialog(this, "你完成了拼图！", "游戏结束", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, new Object[]{"回车继续"}, "重新开始");

        if (time != 0) {
            Record record = new Record(DateUtil.now(), step, time);
            UserManager.addRecord(UserManager.getOnlineUser().getUsername(), record);
        }
        step = 0;
        timer.stop();
        replay();
    }

    private void replay() {
        step = 0;
        time = 0;
        updateInfoDisplay();
        if (timer != null) {
            timer.stop();
        }
        disruptImage();
        requestFocusInWindow();

        imageView.repaint();
    }

    @Override
    public void initComponents() {
        setLayout(new BorderLayout());
        initInfoPanel();
        initImage();
        JPanel panel = new JPanel(new GridBagLayout());
        panel.add(imageView);
        add(panel, BorderLayout.SOUTH);
        add(infoPanel, BorderLayout.NORTH);
    }

    private void initInfoPanel() {
        infoPanel = new JPanel(new FlowLayout());
        stepLabel = new JLabel("步数: 0");
        timeLabel = new JLabel("时间: 0秒");

        infoPanel.add(stepLabel);
        infoPanel.add(Box.createHorizontalStrut(20)); // 添加间隔
        infoPanel.add(timeLabel);

        // 设置标签样式
        Font font = new Font("微软雅黑", Font.BOLD, 20);
        stepLabel.setFont(font);
        timeLabel.setFont(font);
    }

    private void updateInfoDisplay() {
        stepLabel.setText("步数: " + step);
        timeLabel.setText("时间: " + time + "秒");
    }

    @Override
    public void updateMenuBar() {
        JMenu functionMenu = getFunctionMenu();

        JMenuItem restartItem = new JMenuItem("重新开始");
        restartItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0));
        restartItem.addActionListener(_ -> replay());

        JMenuItem randomItem = new JMenuItem("随机图片");
        randomItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0));
        int countOfImagesOriginal = getCountOfImages();
        randomItem.setEnabled(countOfImagesOriginal > 0);
        randomItem.addActionListener(_ -> {
            int countOfImages = getCountOfImages();
            if (countOfImages == 0) {
                randomItem.setEnabled(false);
            } else {
                randomItem.setEnabled(true);
                randomImage(countOfImages);
            }
        });

        JMenuItem addImageItem = new JMenuItem("添加图片");
        addImageItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, 0));
        addImageItem.addActionListener(_ -> addImage());


        JMenuItem usrInfoItem = new JMenuItem("用户信息");
        usrInfoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_H, 0));
        usrInfoItem.addActionListener(_ -> getUserInfo());

        JMenuItem logoutItem = new JMenuItem("退出登录");
        logoutItem.addActionListener(_ -> logout());

        addAll(functionMenu, restartItem, randomItem);
        functionMenu.addSeparator();
        addAll(functionMenu, addImageItem, usrInfoItem);
        functionMenu.addSeparator();
        addAll(functionMenu, logoutItem);
    }

    private void logout() {
        int i = JOptionPane.showOptionDialog(this, "确定要退出登录吗？", "退出登录",
                JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE,
                null, new Object[]{"确定", "取消"}, "取消");
        if (i == JOptionPane.YES_OPTION) {
            // 调用统一的登出逻辑
            UserManager.removeRunData();
            new LoginGUI();
            dispose();
        }

    }

    private void randomImage(int count) {
        Random r = new Random();
        int id = r.nextInt(count) + 1;
        this.dirPath = JsonRW.getStr(JsonRW.configFile, "runPath") + "/" + id;
        imageView.loadOrUpdateImageResources(dirPath, rows, cols);
        disruptImage();
        imageView.repaint();
    }

    private int getCountOfImages() {
        String imageDirPath = JsonRW.getStr(JsonRW.configFile, "userDataDir") + "/" + UserManager.getOnlineUser().getUsername() + "/images";
        File imageDir = new File(imageDirPath);
        if (!imageDir.exists()) {
            return 0;
        }
        int cnt = 0;
        for (File file : Objects.requireNonNull(imageDir.listFiles())) {
            if (file.isFile()) {
                cnt++;
            }
        }
        return cnt;
    }

    private void initImage() {
        imageView = new ImageView(dirPath, rows, cols);
        imageView.setData(new int[rows][cols]);
        disruptImage();
    }

    private void addImage() {
        GUIUtil.showFileSelectionDialog(this, "选择一张图片（尽量是方形的）", filePath -> {
            UserManager.addImage(UserManager.getOnlineUser().getUsername(), filePath);
            JOptionPane.showMessageDialog(this, "添加成功！");
        });
    }

    private void getUserInfo() {
        new UserInfoGUI(this);
        this.setVisible(false);
    }

    private void recoverImage() {
        int[][] data = new int[rows][cols];
        for (int i = 0; i < rows * cols - 1; i++) {
            data[i / rows][i % cols] = i + 1;
        }
        data[rows - 1][cols - 1] = 0;
        x = rows - 1;
        y = cols - 1;
        imageView.setData(data);
        imageView.repaint();
    }

    private void disruptImage() {
        recoverImage();
        Random r = new Random();
        for (int i = 0; i < JsonRW.getInt(JsonRW.configFile, "randomCount"); i++) {
            move(r.nextInt(4) + 37);
        }
        step = 0;
        imageView.repaint();
    }

    /**
     * 交换位置 -因为swing坐标系x, y与数组坐标系x, y相反，所以参数x参数y在取值的时候会对调
     *
     * @param newX 新位置的x坐标
     * @param newY 新位置的y坐标
     */
    @SuppressWarnings("all")
    private void swap(int newX, int newY) {
        if (x == newX && y == newY) {
            return;
        }
        int temp = imageView.getDataElement(y, x);

        imageView.setDateElement(y, x, imageView.getDataElement(newY, newX));
        imageView.setDateElement(newY, newX, temp);
        x = newX;
        y = newY;
    }

    private void move(int VK_CODE) {
        switch (VK_CODE) {
            case KeyEvent.VK_LEFT:
                if (x != 0) {
                    swap(x - 1, y);
                    step++;
                }
                break;
            case KeyEvent.VK_UP:
                if (y != 0) {
                    swap(x, y - 1);
                    step++;
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (x != cols - 1) {
                    swap(x + 1, y);
                    step++;
                }
                break;
            case KeyEvent.VK_DOWN:
                if (y != rows - 1) {
                    swap(x, y + 1);
                    step++;
                }
                break;
        }
    }
}
